package com.share.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class AnnotationUtil {
    /**
     * 提取类或接口上面 特定注解的class
     *
     * @param basePackage     "com.syq"
     * @param annotationClazz "需要检索的注解"
     * @return
     */
    public static Map<Class, Annotation> findClassWithAnnotation(String basePackage, Class annotationClazz) {
        final String RESOURCE_PATTERN = "/**/*.class";
        Map<Class, Annotation> handlerMap = new HashMap<>();

        try {
            //spring工具类，可以获取指定路径下的全部类
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            String pattern = resolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN;
            Resource[] resources = resolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = readerfactory.getMetadataReader(resource);
                //扫描到的class
                String className = reader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(className);
                //判断是否有指定主解
                Annotation anno = clazz.getAnnotation(annotationClazz);
                if (anno != null) {
                    //将注解中的类型值作为key，对应的类作为 value
                    handlerMap.put(clazz, anno);
                }
            }
        } catch (Exception e) {
            log.error("提取注解{}异常", annotationClazz, e);
        }
        return handlerMap;
    }
}
